package com.etone.android.test.utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.util.Log;

import com.etone.android.test.constants.AndroidTestConstants;
import com.etone.android.test.constants.LogType;
import com.jayway.android.robotium.solo.Solo;

/**
 * XML解析并调目标方法类
 * 
 * @author ZhangQiude
 * 
 */
public class RobotiumTestUtils {
	/**
	 * 要解析的XMl文件完全路径
	 */
	private String filePath;
	/**
	 * 记录XML日志类
	 */
	private Log2XmlUtils logXml;
	/**
	 * 用于判断解析是否继续
	 */
	private boolean isContinue;
	/**
	 * Robotium测试API
	 */
	private Solo solo;

	/**
	 * 不记录XML日志构造函数
	 * 
	 * @param filePath
	 * @param solo
	 */
	public RobotiumTestUtils(String filePath, Solo solo) {
		super();
		this.filePath = filePath;
		this.solo = solo;
		this.isContinue = true;
	}

	/**
	 * 记录XML日志构造函数
	 * 
	 * @param filePath
	 * @param solo
	 * @param logXml
	 */
	public RobotiumTestUtils(String filePath, Solo solo, Log2XmlUtils logXml) {
		this(filePath, solo);
		this.logXml = logXml;
	}

	/**
	 * 开始解析
	 */
	public void parse() {
		DocumentBuilderFactory factory = null;
		DocumentBuilder builder = null;
		Document document = null;
		InputStream inputStream = null;
		// 首先找到xml文件
		factory = DocumentBuilderFactory.newInstance();
		try {
			// 找到xml，并加载文档
			builder = factory.newDocumentBuilder();
			inputStream = new FileInputStream(filePath);
			document = builder.parse(inputStream);
			// 找到根Element
			Element root = document.getDocumentElement();
			if (root != null) {
				// 获取结点列表
				NodeList nodeList = root.getChildNodes();
				// 解析NodeList
				if (nodeList != null)
					parseNodeList(nodeList);
			}

		} catch (ParserConfigurationException e) {
			Log.e(AndroidTestConstants.LOG_TAG, e.getMessage());

		} catch (FileNotFoundException e) {
			Log.e(AndroidTestConstants.LOG_TAG, e.getMessage());

		} catch (SAXException e) {
			Log.e(AndroidTestConstants.LOG_TAG, e.getMessage());

		} catch (IOException e) {
			Log.e(AndroidTestConstants.LOG_TAG, e.getMessage());

		} catch (Exception e) {
			Log.e(AndroidTestConstants.LOG_TAG, e.getMessage());

		}

		// 保存日志
		if (logXml != null)
			logXml.save();

	}

	/**
	 * 解析结点
	 * 
	 * @param nodeList
	 */
	private void parseNodeList(NodeList nodeList) {

		for (int i = 0; i < nodeList.getLength(); i++) {
			// 如果isContinue不为真,跳出循环
			if (!isContinue)
				break;
			// 获取结点
			Node node = nodeList.item(i);
			// 判断node是不是Element
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				
				Element element = (Element) node;
				// 标签名
				String tagName = element.getTagName();
				// 方法
				String method = null;
				// 参数
				String[] param = null;
				// 反射调用方法参数类型
				Class<?>[] cls = null;
				// 反射调用方法参数值
				Object[] objs = null;

				boolean isTestNext = true;
				if ("if".equals(tagName)) {
					method = element.getAttribute("method");
					String paramStr = element.getAttribute("param");
					param = paramStr.split(";");
					// 解析参数
					List<Object> list = parseParam(param);
					cls = (Class[]) list.get(0);
					objs = (Object[]) list.get(1);
					try {
						// 反射调用
						isTestNext = (Boolean) ReflectionUtils.invokeMethod(
								solo, method, cls, objs);
						// 记录日志
						if (isTestNext && logXml != null)
							logXml.addNode(LogType.Info, method + "#"
									+ paramStr + "|return:" + isTestNext, "");
						else if (!isTestNext && logXml != null)
							logXml.addNode(LogType.Info, method + "#"
									+ paramStr + "|return:" + isTestNext, "");
						// 判断Element是否有子结点
						if (element.hasChildNodes()) {
							// 获取result结点
							NodeList childNodeList = element
									.getElementsByTagName("result");
							if (isTestNext) {
								// true时
								parseNodeList(childNodeList.item(0)
										.getChildNodes());
							} else {
								// false时
								parseNodeList(childNodeList.item(1)
										.getChildNodes());
							}
						}
					} catch (Exception e) {
						Log.e(AndroidTestConstants.LOG_TAG, e.getMessage());
						if (logXml != null)
							logXml.addNode(LogType.Error, method,
									e.getMessage());
					}

				} else if ("todo".equals(tagName)) {
					method = element.getAttribute("method");
					String paramStr = element.getAttribute("param");
					param = paramStr.split(";");
					// 解析参数
					List<Object> list = parseParam(param);
					cls = (Class[]) list.get(0);
					objs = (Object[]) list.get(1);
					// 反射调用
					try {
						ReflectionUtils.invokeMethod(solo, method, cls, objs);
						// 记录日志
						if (logXml != null)
							logXml.addNode(LogType.Info, method + "#"
									+ paramStr, "");
					} catch (Exception e) {
						Log.e(AndroidTestConstants.LOG_TAG, e.getMessage());
						if (logXml != null)
							logXml.addNode(LogType.Error, method + "#"
									+ paramStr, e.getMessage());
					}
				} else if ("takeScreenShot".equals(tagName)) {
					String subPath = filePath.substring(0,
							filePath.lastIndexOf("/"));
					// 图片存放路径
					String photoPath = subPath.substring(0,
							subPath.lastIndexOf("/") + 1)
							+ "img/";
					// 图片名
					String photoName = DateUtils
							.convertDateToNameString(new Date());
					// 截图
					try {
						ViewUtils.takeScreenShot(solo.getCurrentViews().get(0),
								photoName, photoPath);
						if (logXml != null)
							logXml.addNode(LogType.Photo, "takeScreenShot--> "
									+ photoPath + photoName + ".jpg", "");
					} catch (Exception e) {
						Log.e(AndroidTestConstants.LOG_TAG, e.getMessage());
						if (logXml != null)
							logXml.addNode(LogType.Error, "takeScreenShot--> "
									+ photoPath + photoName + ".jpg",
									e.getMessage());
					}
				} else if ("break".equals(tagName)) {
					// 让测试退出
					isContinue = false;
					// 记录日志
					if (logXml != null) {
						// 找到If结点
						Element parenElement = (Element) element
								.getParentNode().getParentNode();
						String invokeMethod = parenElement
								.getAttribute("method");
						String invokeParam = parenElement.getAttribute("param");

						logXml.addNode(LogType.Error, invokeMethod + "#"
								+ invokeParam, "程序启动失败!");
					}
				} else if ("continue".equals(tagName)) {
					continue;
				}
			}
			node = null;
		}

	}

	/**
	 * 解析参数
	 * 
	 * @param param
	 * @return
	 */
	private List<Object> parseParam(String[] param) {

		List<Object> list = new ArrayList<Object>();
		Class<?>[] cls = new Class[param.length];
		Object[] objs = new Object[param.length];

		for (int i = 0; i < param.length; i++) {

			String[] str = param[i].split(":");

			if ("int".equals(str[0])) {
				cls[i] = int.class;
				objs[i] = Integer.parseInt(str[1]);
			} else if ("float".equals(str[0])) {
				cls[i] = float.class;
				objs[i] = Float.parseFloat(str[1]);
			} else if ("long".equals(str[0])) {
				cls[i] = long.class;
				objs[i] = Long.parseLong(str[1]);
			} else if ("String".equals(str[0])) {
				cls[i] = String.class;
				objs[i] = str[1];
			} else if ("boolean".equals(str[0])) {
				cls[i] = boolean.class;
				objs[i] = Boolean.parseBoolean(str[1]);
			}
		}
		list.add(cls);
		list.add(objs);

		return list;
	}

}
